package jmine.tec.web.wicket.component.table;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jmine.tec.report.api.table.ReportCell;
import jmine.tec.report.api.table.ReportRow;
import jmine.tec.report.api.table.ReportTable;
import jmine.tec.report.impl.table.ReportCellImpl;
import jmine.tec.web.wicket.component.InlinedAjaxCheckBox;
import jmine.tec.web.wicket.component.InlinedCheckBox;
import jmine.tec.web.wicket.component.command.TableCommandsProvider;
import jmine.tec.web.wicket.component.command.button.SearchCommandHandler;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;

/**
 * {@link SearchResultAjaxSelectionTableBuilder} para criar o markup de um Report
 * 
 * @author Rafael Volpato
 * @param <BO> tipo da entidade
 */
public class SearchResultAjaxSelectionTableBuilder<BO> extends SearchResultTableBuilder<BO> {

    private static final double SELECT_COLUMN_WIDTH = 0.1;

    private Set<Serializable> chosen;

    private List<InlinedCheckBox> checkboxes;

    private Boolean selectAll = Boolean.FALSE;

    /**
     * Construtor.
     * 
     * @param targetClass targetClass
     * @param searchHandler {@link SearchCommandHandler}
     * @param commandsProvider {@link TableCommandsProvider}
     * @param chosen armazena os elementos que foram selecionados
     */
    public SearchResultAjaxSelectionTableBuilder(Class<BO> targetClass, SearchCommandHandler<BO> searchHandler,
            TableCommandsProvider commandsProvider, Set<Serializable> chosen) {
        super(targetClass, searchHandler, commandsProvider);
        this.chosen = chosen;
        this.checkboxes = new ArrayList<InlinedCheckBox>();
    }

    /**
     * @return the selectAll
     */
    public Boolean getSelectAll() {
        return this.selectAll;
    }

    /**
     * @param selectAll the selectAll to set
     */
    public void setSelectAll(Boolean selectAll) {
        this.selectAll = selectAll;
    }

    /**
     * cria uma lista com {@link ICellPopulator} para as linhas da tabela
     * 
     * @param table {@link ReportTable}
     * @return {@link List}
     */
    @Override
    @SuppressWarnings("unchecked")
    protected List<ICellPopulator<ReportRow>> getCellPopulators(ReportTable table) {
        List<ICellPopulator<ReportRow>> cellPopulators = super.getCellPopulators(table);

        ICellPopulator checkboxCellPopulator = new ICellPopulator<ReportRow>() {
            public void detach() {
            }

            public void populateItem(Item<ICellPopulator<ReportRow>> cellItem, String componentId, IModel<ReportRow> rowModel) {
                Map<String, ReportCell> cellMap = rowModel.getObject().getCellMap();
                ReportCell cellValue = cellMap.get("pk");
                Long pk = Long.valueOf(String.valueOf(cellValue.getValue()));
                SelectEntityModel checkModel = new SelectEntityModel(SearchResultAjaxSelectionTableBuilder.this.chosen, pk);
                InlinedCheckBox checkBox = new InlinedCheckBox(componentId, checkModel);
                checkBox.setOutputMarkupId(true);
                SearchResultAjaxSelectionTableBuilder.this.checkboxes.add(checkBox);
                cellItem.add(checkBox);
            }
        };
        cellPopulators.add(0, checkboxCellPopulator);

        return cellPopulators;
    }

    /**
     * Cria um header
     * 
     * @param reportElement {@link ReportTable}
     * @return {@link ListView}
     */
    @Override
    protected ListView<ReportCell> createColumnHeader(ReportTable reportElement) {
        ListView<ReportCell> lvCells = super.createColumnHeader(reportElement);
        List<ReportCell> reportCells = lvCells.getModelObject();
        ReportCellImpl reportCellImpl = new ReportCellImpl("selectionBox");
        this.createRPI(reportCellImpl).setRelativeWidth(SELECT_COLUMN_WIDTH);
        reportCells.add(0, reportCellImpl);
        lvCells.setModelObject(reportCells);
        return lvCells;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected ListView<ReportCell> doCreateHeaderListView(List<ReportCell> header) {
        final double totalWidth = this.sumRelativeWidth(header);

        return new ListView<ReportCell>("columns", header) {
            @Override
            protected void populateItem(ListItem<ReportCell> item) {
                ReportCell reportCell = item.getModelObject();
                String cellValue = SearchResultAjaxSelectionTableBuilder.this.renderReportCell(reportCell);

                if ("selectionBox".equals(cellValue)) {
                    item.add(new InlinedAjaxCheckBox("cell", new PropertyModel<Boolean>(SearchResultAjaxSelectionTableBuilder.this,
                            "selectAll")) {
                        @Override
                        protected void onUpdate(AjaxRequestTarget target) {
                            // XXX rafael.volpato: Tirar esse for, os checkboxes deveriam ser atualizados todos de uma vez, e não um request
                            // ajax p/ cada check
                            for (InlinedCheckBox check : SearchResultAjaxSelectionTableBuilder.this.checkboxes) {
                                target.addComponent(check);
                                check.getCheckBox().getModel().setObject(SearchResultAjaxSelectionTableBuilder.this.selectAll);
                            }
                        }
                    });
                } else {
                    Label cell = new Label("cell", cellValue);
                    String widthCell = SearchResultAjaxSelectionTableBuilder.this.widthCalculate(reportCell, totalWidth);
                    cell.add(new SimpleAttributeModifier("width", widthCell));
                    item.add(cell);
                }
            }
        };
    }
}
